"""Parse and unparse lambda calculus expressions."""
from parsing import utils as pUtils

from utils import *

def parse(s):
    """
    Transform a lambda-calculus expression into a parse tree for evaluation.
    
    The result is a node (one of the following):
    a. a name (1-char string)
    b. a function (a list with 2 values):
        1. parameter string ('/ab')
        2. body (list of elements)
    c. a list of nodes

    >>> parse('x')
    'x'
    >>> parse('/x.x')
    ['/x', ['x']]
    >>> parse('(/x.x)y')
    [['/x', ['x']], 'y']
    >>> parse('(/x.x/y.xy)((/x.x)z)/x.x')
    [['/x', ['x', ['/y', ['x', 'y']]]], [['/x', ['x']], 'z'], ['/x', ['x']]]
    """
    result = []
    i = 0
    while i < len(s):
        char = s[i]
        if char == '(':
            start, end = pUtils.findMatching(s, '(', ')', startI=i)
            inner = parse(s[start + 1: end - 1])
            result.append(inner if len(inner) > 1 else inner[0])
            i = end
        elif char == FUNC_CHAR:
            params, body = s[i:].split('.', 1)
            body = parse(body)
            result.append([params, list(body)])
            break
        else:
            result.append(char)
            i += 1
    return result if len(result) > 1 else result[0]

def unparse(node):
    """
    Return a string representation of a node.

    >>> unparse('s')
    's'
    >>> unparse(['s'])
    's'
    >>> unparse(['/x', ['x']])
    '/x.x'
    >>> unparse([['/x', ['x']], 'y'])
    '(/x.x)y'
    >>> unparse([['/x', ['x', ['/y', ['x', 'y']]]], [['/x', ['x']], 'z'], ['/x', ['x']]])
    '(/x.x/y.xy)((/x.x)z)/x.x'
    """
    if isName(node):
        return node
    if isFunc(node):
        params, body = splitFunc(node)
        return FUNC_CHAR + params + '.' + unparse(body)

    result = ''
    for innerNode in node[:-1]:
        if isName(innerNode):
            result += unparse(innerNode)
        else:
            result += '(%s)' % unparse(innerNode)
    if isCompound(node[-1]):
        result += '(%s)' % unparse(node[-1])
    else:
        result += unparse(node[-1])
    return result

if __name__ == '__main__':
    import doctest

    doctest.testmod()
